﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.Remoting.Channels;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 运动控制卡Demo
{
    public partial class FrmMain : Form
    {
        // 轴号
        public short Axis { get => Convert.ToInt16(comboBoxAxis.Text); }
        // 指令的返回值
        private short rtn;
        public FrmMain()
        {
            InitializeComponent();
            // 默认选中轴1
            comboBoxAxis.SelectedIndex = 0;
            
        }

        #region 初始化
        private void btnInit_Click(object sender, EventArgs e)
        {
            // 打开运动控制卡
            // channel: 0:正常打开运动控制器。(默认值为: 0)，1:内部调试方式，用户不能使用。
            // param: 当channel = 1时，该参数有效
            rtn = gts.mc.GT_Open(0, 1);
            if (rtn != 0)
            {
                MessageBox.Show("打开运动控制卡失败：" + rtn);
                return;
            }
            // 控制卡复位
            rtn = gts.mc.GT_Reset();
            // 加载配置文件
            rtn = gts.mc.GT_LoadConfig("GTS800.cfg");
            // 清除状态
            // axis: 起始轴号。正整数。
            // count: 读取的轴数，默认为1。正整数。
            // rtn = gts.mc.GT_ClrSts(1, 8);
            // 开启定时器
            timer1.Start();

        }
        
        private void btnClear_Click(object sender, EventArgs e)
        {
            // 清除状态
            // axis: 起始轴号。正整数。
            // count: 读取的轴数，默认为1。正整数。
            rtn = gts.mc.GT_ClrSts(1, 8);
        }

        private void btnOpen_Click(object sender, EventArgs e)
        {
            if (btnOpen.Text == "伺服使能关闭中")
            {
                rtn = gts.mc.GT_AxisOff(Axis);
            }
            else
            {
                rtn = gts.mc.GT_AxisOn(Axis);
            }
            Console.WriteLine("rtn：" + rtn);
        }
        private void btnZero_Click(object sender, EventArgs e)
        {
            rtn = gts.mc.GT_ZeroPos(1, 8);
            Console.WriteLine("rtn：" + rtn);
        }


        #endregion

        #region 选择轴号下拉改变事件

        private void comboBoxAxis_SelectedIndexChanged(object sender, EventArgs e)
        {
            // 轴状态
            int pSts = 0;
            // 读取控制器时钟，默认值为：NULL
            uint pClock = 0;

            // 读取轴状态
            rtn = gts.mc.GT_GetSts(Axis, out pSts, 1, out pClock);
            if ((pSts & 0x2) != 0)
            {
                Console.Write("驱动器报警");
                pQuDong.BackColor = Color.Red;
            }
            else
            {
                Console.Write("驱动器未报警");
                pQuDong.BackColor = Color.Yellow;
            }
            
            if ((pSts & 0x20) != 0)
            {
                Console.WriteLine("正限位触发了");
                pZheng.BackColor = Color.Red;
            }
            else
            {
                Console.WriteLine("正限位未触发");

                pZheng.BackColor = Color.Yellow;
            }
            if ((pSts & 0x40) != 0)
            {
                Console.WriteLine("负限位触发了");
                pFu.BackColor = Color.Red;
            }
            else
            {
                Console.WriteLine("负限位未触发");

                pFu.BackColor = Color.Yellow;
            }
            if ((pSts & 0x200) != 0)
            {
                btnOpen.Text = "伺服使能关闭中";
                pShiNeng.BackColor = Color.Red;
            }
            else
            {
                btnOpen.Text = "伺服使能开启中";
                pShiNeng.BackColor = Color.Yellow;
            }
        }

        #endregion

        #region 点位运动

        // 开启点位运动模式
        private void btnTrap_Click(object sender, EventArgs e)
        {
            rtn = gts.mc.GT_PrfTrap(Axis);
            Console.WriteLine("rtn：" + rtn);
        }
        // 开始运动
        int pos = 0, vel = 0;
        private void btnStart_Click(object sender, EventArgs e)
        {
            // 定义点位运动结构体变量
            gts.mc.TTrapPrm trapPrm;
            // 获取当前轴之前的点位运动信息
            rtn = gts.mc.GT_GetTrapPrm(Axis, out trapPrm);
            // 设置加/减速度
            trapPrm.acc = 0.5;
            trapPrm.dec = 0.5;
            // 设置平滑时间
            trapPrm.smoothTime = 1;
            // 设置点位运动参数
            rtn = gts.mc.GT_SetTrapPrm(Axis, ref trapPrm);
            // 累加规划位置的偏移（否则不动，不想累加需要位置清零）
            pos += Convert.ToInt32(txtTrapPos.Text);
            // 获取点位速度
            vel = Convert.ToInt32(txtTrapVel.Text);
            // 设置点位运动的距离和速度
            rtn = gts.mc.GT_SetPos(Axis, pos);
            rtn = gts.mc.GT_SetVel(Axis, vel);
            // 开启点位运动
            rtn = gts.mc.GT_Update(1 << (Axis - 1));

        }
        // 结束运动
        private void btnStop_Click(object sender, EventArgs e)
        {
            // 停止运动
            rtn = gts.mc.GT_Stop(1 << (Axis - 1), 0);
        }


        #endregion

        #region 点动Jog运动

        // 开启点动运动
        private void btnJog_Click(object sender, EventArgs e)
        {
            rtn = gts.mc.GT_PrfJog(Axis);
            // 设置运行参数
            gts.mc.TJogPrm jogPrm;
            rtn = gts.mc.GT_GetJogPrm(Axis, out jogPrm);
            // 设置加速度、减速度、平滑参数
            jogPrm.acc = 0.1;                                               
            jogPrm.dec = 0.1;
            rtn = gts.mc.GT_SetJogPrm(Axis, ref jogPrm);
            
            // 
        }

        // 正向运动
        private void btnZheng_MouseDown(object sender, MouseEventArgs e)
        {
            // 设置点动速度
            rtn = gts.mc.GT_SetVel(Axis, - Convert.ToDouble(txtJogVel.Text.Trim()));
            // 更新轴运动
            rtn = gts.mc.GT_Update(1 << (Axis - 1));
        }

        private void btnZheng_MouseUp(object sender, MouseEventArgs e)
        {
            rtn = gts.mc.GT_Stop(1 << (Axis - 1),0);
        }

        private void btnFu_MouseDown(object sender, MouseEventArgs e)
        {
            // 设置点动速度
            rtn = gts.mc.GT_SetVel(Axis, Convert.ToDouble(txtJogVel.Text.Trim()));
            // 更新轴运动
            rtn = gts.mc.GT_Update(1 << (Axis - 1));
        }

        private void btnFu_MouseUp(object sender, MouseEventArgs e)
        {
            rtn = gts.mc.GT_Stop(1 << (Axis - 1), 0);
        }

        #endregion

        #region 定时器事件

        private void timer1_Tick(object sender, EventArgs e)
        {
            // 检测轴状态
            comboBoxAxis_SelectedIndexChanged(null, null);
            // 检测位置和速度
            getPosAndVel();
            getDOStatus();
            getDIStatus();
        }
        // 检测位置和速度
        double prfPos, prfVel, encPos, encVel;
        uint pvClock;
        private void getPosAndVel()
        {
            // 读取规划位置和规划速度
            rtn = gts.mc.GT_GetPrfPos(Axis, out prfPos, 1, out pvClock);
            rtn = gts.mc.GT_GetPrfVel(Axis, out prfVel, 1, out pvClock);
            // 读取实际位置和实际速度
            rtn = gts.mc.GT_GetEncPos(Axis, out encPos, 1, out pvClock);
            rtn = gts.mc.GT_GetEncVel(Axis, out encVel, 1, out pvClock);
            // 展示
            txtPrfpos.Text = prfPos.ToString();
            txtPrfvel.Text = prfVel.ToString();
            txtEncpos.Text = encPos.ToString();
            txtEncvel.Text = encVel.ToString();
        }

        #endregion

        #region 插补运动
        
        // 建立坐标系
        private void btnCrd_Click(object sender, EventArgs e)
        {
            // 建立坐标系的参数信息
            gts.mc.TCrdPrm crdPrm = new gts.mc.TCrdPrm();
            // 给各参数赋值
            crdPrm.dimension = 2;
            // 坐标系的最大合成速度是: 500 pulse / ms
            crdPrm.synVelMax = 500;
            // 坐标系的最大合成加速度是:2 pulse/ms^2
            crdPrm.synAccMax = 2;
            // 坐标系的最小匀速时间为0
            crdPrm.evenTime = 0;
            // 规划器1对应到x轴
            crdPrm.profile1 = 1;
            //规划器2对应到Y轴
            crdPrm.profile2 = 2;
            // 需要设置加工坐标系原点位置
            crdPrm.setOriginFlag = 1;
            // 加工坐标系原点位置在(0,0,0)，即与机床坐标系原点重合
            crdPrm.originPos1 = 0;
            crdPrm.originPos2 = 0;
            // 建立坐标系
            // 参数1: 坐标系号，取值范围:[1，2]
            // 参数2: 坐标系的参数信息
            rtn = gts.mc.GT_SetCrdPrm(1, ref crdPrm);
            Console.WriteLine("rtn：" + rtn);
        }
        // 绘制线
        private void btnLine_Click(object sender, EventArgs e)
        {
            // 即将把数据存入坐标系1的FIFO0中，所以要首先清除此缓存区中的数据
            rtn = gts.mc.GT_CrdClear(1, 0);
            rtn = gts.mc.GT_LnXY(
                 1,				// 该插补段的坐标系是坐标系1
                10000, 30000,		// 该插补段的终点坐标(10000, 30000)
                50,				// 该插补段的目标速度：50pulse/ms
                0.2,				// 插补段的加速度：0.2pulse/ms^2
                0,				// 终点速度为0
                0);             // 向坐标系1的FIFO0缓存区传递该直线插补数据
            // 向缓存区写入第二段插补数据
            rtn = gts.mc.GT_LnXY(1, 20000, 0, 50, 0.2, 0, 0);
            // 缓存区延时指令
            rtn = gts.mc.GT_BufDelay(
                1,				// 坐标系是坐标系1
                500,				// 延时500ms
                0);				// 向坐标系1的FIFO0缓存区传递该延时
            // 向缓存区写入第三段插补数据
            rtn = gts.mc.GT_LnXY(1, 30000, 30000, 50, 0.2, 0, 0);
            int pSpace = 0;
            rtn = gts.mc.GT_CrdSpace(1, out pSpace, 0);
            Console.WriteLine("pSpace = " + pSpace);
            // 启动坐标系1的FIFO0的插补运动
            rtn = gts.mc.GT_CrdStart(1, 0);
            // 等待运动完成
            short pRun = 0; // 读取插补运动状态。0:该坐标系的该FIFO没有在运动;1:该坐标系的该FIF0正在进行插补运动。
            int pSegment = 0;   // 读取当前已经完成的插补段数
            rtn = gts.mc.GT_CrdStatus(1, out pRun, out pSegment, 0);
            do
            {
                Console.WriteLine($"正在进行插补运动中...剩余{pSegment}段");
                rtn = gts.mc.GT_CrdStatus(1, out pRun, out pSegment, 0);
            } while (rtn == 1);
        }
        // 绘制弧
        private void btnArc_Click(object sender, EventArgs e)
        {
            rtn = gts.mc.GT_CrdClear(1, 0);
            rtn = gts.mc.GT_ArcXYR(1, 0, 20000, 10000, 0, 50, 0.5, 0, 0);
            int pSpace = 0;
            rtn = gts.mc.GT_CrdSpace(1, out pSpace, 0);
            Console.WriteLine("pSpace = " + pSpace);
            // 启动坐标系1的FIFO0的插补运动
            rtn = gts.mc.GT_CrdStart(1, 0);
            // 等待运动完成
            short pRun = 0; // 读取插补运动状态。0:该坐标系的该FIFO没有在运动;1:该坐标系的该FIF0正在进行插补运动。
            int pSegment = 0;   // 读取当前已经完成的插补段数
            rtn = gts.mc.GT_CrdStatus(1, out pRun, out pSegment, 0);
            do
            {
                Console.WriteLine($"正在进行插补运动中...剩余{pSegment}段");
                rtn = gts.mc.GT_CrdStatus(1, out pRun, out pSegment, 0);
            } while (rtn == 1);
        }
        // 绘制圆
        private void btnCircle_Click(object sender, EventArgs e)
        {
            rtn = gts.mc.GT_CrdClear(1, 0);
            // 圆插补（圆的终点一定是当前位置，否则报7，参数错误）
            rtn = gts.mc.GT_ArcXYC(1, 0, 0, 0, 20000,0, 50, 0.5, 0, 0);
            int pSpace = 0;
            rtn = gts.mc.GT_CrdSpace(1, out pSpace, 0);
            Console.WriteLine("pSpace = " + pSpace);
            // 启动坐标系1的FIFO0的插补运动
            rtn = gts.mc.GT_CrdStart(1, 0);
            // 等待运动完成
            short pRun = 0; // 读取插补运动状态。0:该坐标系的该FIFO没有在运动;1:该坐标系的该FIF0正在进行插补运动。
            int pSegment = 0;   // 读取当前已经完成的插补段数
            rtn = gts.mc.GT_CrdStatus(1, out pRun, out pSegment, 0);
            do
            {
                Console.WriteLine($"正在进行插补运动中...剩余{pSegment}段");
                rtn = gts.mc.GT_CrdStatus(1, out pRun, out pSegment, 0);
            } while (rtn == 1);
        }
        // 绘制三角形
        private void btntriangle_Click(object sender, EventArgs e)
        {
            rtn = gts.mc.GT_CrdClear(1, 0);
            rtn = gts.mc.GT_LnXY(1, 15000, 15000, 50, 0.2, 0, 0);         
            rtn = gts.mc.GT_LnXY(1, 30000, 0, 50, 0.2, 0, 0);
            rtn = gts.mc.GT_LnXY(1, 0, 0, 50, 0.2, 0, 0);
            int pSpace = 0;
            rtn = gts.mc.GT_CrdSpace(1, out pSpace, 0);
            Console.WriteLine("pSpace = " + pSpace);
            // 启动坐标系1的FIFO0的插补运动
            rtn = gts.mc.GT_CrdStart(1, 0);
            // 等待运动完成
            short pRun = 0; // 读取插补运动状态。0:该坐标系的该FIFO没有在运动;1:该坐标系的该FIF0正在进行插补运动。
            int pSegment = 0;   // 读取当前已经完成的插补段数
            rtn = gts.mc.GT_CrdStatus(1, out pRun, out pSegment, 0);
            do
            {
                Console.WriteLine($"正在进行插补运动中...剩余{pSegment}段");
                rtn = gts.mc.GT_CrdStatus(1, out pRun, out pSegment, 0);
            } while (rtn == 1);
        }

        

        // 绘制矩形
        private void btnrectangle_Click(object sender, EventArgs e)
        {
            rtn = gts.mc.GT_CrdClear(1, 0);
            rtn = gts.mc.GT_LnXY(1, 0, 20000, 50, 0.2, 0, 0);
            rtn = gts.mc.GT_LnXY(1, 20000, 20000, 50, 0.2, 0, 0);
            rtn = gts.mc.GT_LnXY(1, 20000, 0, 50, 0.2, 0, 0);
            rtn = gts.mc.GT_LnXY(1, 0, 0, 50, 0.2, 0, 0);
            int pSpace = 0;
            rtn = gts.mc.GT_CrdSpace(1, out pSpace, 0);
            Console.WriteLine("pSpace = " + pSpace);
            // 启动坐标系1的FIFO0的插补运动
            rtn = gts.mc.GT_CrdStart(1, 0);
            // 等待运动完成
            short pRun = 0; // 读取插补运动状态。0:该坐标系的该FIFO没有在运动;1:该坐标系的该FIF0正在进行插补运动。
            int pSegment = 0;   // 读取当前已经完成的插补段数
            rtn = gts.mc.GT_CrdStatus(1, out pRun, out pSegment, 0);
            do
            {
                Console.WriteLine($"正在进行插补运动中...剩余{pSegment}段");
                rtn = gts.mc.GT_CrdStatus(1, out pRun, out pSegment, 0);
            } while (rtn == 1);
        }
        // 绘制五角星
        private void btnStar_Click(object sender, EventArgs e)
        {
            rtn = gts.mc.GT_CrdClear(1, 0);
            rtn = gts.mc.GT_LnXY(1, 7000, 9000, 50, 0.2, 0, 0);
            rtn = gts.mc.GT_LnXY(1, -1000, 9000, 50, 0.2, 0, 0);
            rtn = gts.mc.GT_LnXY(1, 6000, 0, 50, 0.2, 0, 0);
            rtn = gts.mc.GT_LnXY(1, 3000, 12000, 50, 0.2, 0, 0);
            rtn = gts.mc.GT_LnXY(1, 0, 0, 50, 0.2, 0, 0);
            int pSpace = 0;
            rtn = gts.mc.GT_CrdSpace(1, out pSpace, 0);
            Console.WriteLine("pSpace = " + pSpace);
            // 启动坐标系1的FIFO0的插补运动
            rtn = gts.mc.GT_CrdStart(1, 0);
            // 等待运动完成
            short pRun = 0; // 读取插补运动状态。0:该坐标系的该FIFO没有在运动;1:该坐标系的该FIF0正在进行插补运动。
            int pSegment = 0;   // 读取当前已经完成的插补段数
            rtn = gts.mc.GT_CrdStatus(1, out pRun, out pSegment, 0);
            do
            {
                Console.WriteLine($"正在进行插补运动中...剩余{pSegment}段");
                rtn = gts.mc.GT_CrdStatus(1, out pRun, out pSegment, 0);
            } while (rtn == 1);
        }
        #endregion

        #region DO和DI操作
        // 读取数字IO输出状态
        private void getDOStatus()
        {
            // 读取到的DO状态
            int pValue;
            rtn = gts.mc.GT_GetDo(gts.mc.MC_GPO, out pValue);
            // DO0
            if ((pValue & (1 << 0)) == 0)
            {
                do0.LampColor = new Color[] { Color.Yellow };
            }
            else
            {
                do0.LampColor = new Color[] { Color.Red };
            }
            // DO1
            if ((pValue & (1 << 1)) == 0)
            {
                do1.LampColor = new Color[] { Color.Yellow };
            }
            else
            {
                do1.LampColor = new Color[] { Color.Red };
            }
            // DO2
            if ((pValue & (1 << 2)) == 0)
            {
                do2.LampColor = new Color[] { Color.Yellow };
            }
            else
            {
                do2.LampColor = new Color[] { Color.Red };
            }
            // DO3
            if ((pValue & (1 << 3)) == 0)
            {
                do3.LampColor = new Color[] { Color.Yellow };
            }
            else
            {
                do3.LampColor = new Color[] { Color.Red };
            }
            // DO4
            if ((pValue & (1 << 4)) == 0)
            {
                do4.LampColor = new Color[] { Color.Yellow };
            }
            else
            {
                do4.LampColor = new Color[] { Color.Red };
            }

        }
        // 读取数字IO输出状态
        private void getDIStatus()
        {
            // 读取到的DI状态
            int pValue;
            rtn = gts.mc.GT_GetDi(gts.mc.MC_GPI, out pValue);
            // DO1
            if ((pValue & (1 << 0)) == 0)
            {
                di0.LampColor = new Color[] { Color.Yellow };
            }
            else
            {
                di0.LampColor = new Color[] { Color.Red };
            }
        }

        // 气缸下降
        private void btnQGXJ_Click(object sender, EventArgs e)
        {
            // 按位设置数字IO输出状态
            gts.mc.GT_SetDoBit(gts.mc.MC_GPO, 1, 0);
            gts.mc.GT_SetDoBit(gts.mc.MC_GPO, 2, 1);
        }
        // 气缸上升
        private void btnQGSS_Click(object sender, EventArgs e)
        {
            // 按位设置数字IO输出状态
            gts.mc.GT_SetDoBit(gts.mc.MC_GPO, 2, 0);
            gts.mc.GT_SetDoBit(gts.mc.MC_GPO, 1, 1);
        }
        // 抓手松开
        private void btnZSSK_Click(object sender, EventArgs e)
        {
            gts.mc.GT_SetDoBit(gts.mc.MC_GPO, 3, 0);
            gts.mc.GT_SetDoBit(gts.mc.MC_GPO, 4, 1);
        }
        // 抓手抓紧
        private void btnZSZJ_Click(object sender, EventArgs e)
        {
            gts.mc.GT_SetDoBit(gts.mc.MC_GPO, 3, 1);
            gts.mc.GT_SetDoBit(gts.mc.MC_GPO, 4, 0);
        }
        // 传送带
        private void btnCSD_Click(object sender, EventArgs e)
        {
            // 读取到的DI状态
            int pValue;
            rtn = gts.mc.GT_GetDi(gts.mc.MC_GPI, out pValue);
            // DO4
            if ((pValue & (1 << 4)) == 0)
            {
                gts.mc.GT_SetDoBit(gts.mc.MC_GPO, 5, 1);
            }
            else
            {
                gts.mc.GT_SetDoBit(gts.mc.MC_GPO, 5, 0);
            }
            
            
        }
        
        #endregion
    }
}
